package jp.androidgroup.chiba.androidresearch.aws;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;

import jp.androidgroup.chiba.androidresearch.Common;
import jp.androidgroup.chiba.androidresearch.data.Base;

import jp.androidgroup.chiba.androidresearch.R;
import android.content.Context;

import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.simpledb.AmazonSimpleDBClient;
import com.amazonaws.services.simpledb.model.Attribute;
import com.amazonaws.services.simpledb.model.Item;
import com.amazonaws.services.simpledb.model.PutAttributesRequest;
import com.amazonaws.services.simpledb.model.ReplaceableAttribute;
import com.amazonaws.services.simpledb.model.SelectRequest;
import com.amazonaws.services.simpledb.model.SelectResult;

/*
 * AWS SimpleDBクラス
 */
public class Sdb {
	private static AmazonSimpleDBClient sdb;

	// TABLEの頭文字
	private static final String TABLE_PREFIX = "AR_";

	/**
	 * SDBクライアント取得
	 *
	 * @return sdb SDBクライアント
	 */
	public static AmazonSimpleDBClient getSdb(Context cont) {
		if(sdb == null){
			setInstance(cont);
		}
		return sdb;
	}

	/**
	 * AmazonSimpleDBインスタンス生成
	 *
	 * @return AmazonSimpleDB
	 */
	private static void setInstance(Context cont) {
        if ( sdb == null ) {
		    sdb = new AmazonSimpleDBClient(new BasicAWSCredentials(cont.getString(R.string.v_access_key_id), cont.getString(R.string.v_secret_key)));

		    // TOKYOへ接続
		    sdb.setEndpoint(cont.getString(R.string.v_end_point));
        }
	}

	/**
	 * テーブル名を取得
	 * @param pojo　対象クラス
	 * @return
	 */
	public static String getDomainName(Class<?> cls){
		return TABLE_PREFIX + cls.getSimpleName();
	}

	/**
	 * count(*)のクエリー送信
	 * @param query
	 * @return 件数
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public static int queryCount(AmazonSimpleDBClient sdb, String query) throws Exception{
		SelectRequest selectRequest;
		SelectResult selectResult;

		selectRequest = new SelectRequest(query).withConsistentRead( true );
		selectResult = sdb.select( selectRequest );
		List<Item> items1 = selectResult.getItems();
		Attribute i = (Attribute) items1.get(0).getAttributes().get(0);

		return Integer.parseInt(i.getValue());
	}

	/**
	 * Insert文を発行
	 *
	 * @param sdb AmazonSimpleDBClient
	 * @param id  テーブルのID
	 * @param pojo　登録するPojo
	 * @throws Exception
	 */
	public static void insertRequest(AmazonSimpleDBClient sdb, String id, Base pojo) throws Exception {
		int idx;
		String dname;
		String column;
		ArrayList<ReplaceableAttribute> atts;
		PutAttributesRequest request;

		dname = getDomainName(pojo.getClass());
		request = new PutAttributesRequest();
		request.withDomainName(dname);
		request.withItemName(id);
		atts = new ArrayList<ReplaceableAttribute>();
		// カラム分 ReplaceableAttributeを作成する
		for(idx = 0;idx < pojo.getColumns().length;idx++){
			column = pojo.getColumns()[idx];
			atts.add(new ReplaceableAttribute(column,(String) Common.getFieldValueByName(pojo,column), true));
		}
		request.withAttributes(atts);
		// 送信へ
		sdb.putAttributes(request);
	}

	/**
	 * Queryを発行し、データクラスをリストで返す
	 *
	 * @param sdb　 AmazonSimpleDBClient
	 * @param query 発行クエリー
	 * @param pojo　変換するPojo
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static List<?> selectQuery(AmazonSimpleDBClient sdb, String query, Base pojo) throws Exception {
		String key;
		Attribute att;
		List<?> list;
		List<Item> items1;
		SelectRequest selectRequest;
		SelectResult selectResult;
		LinkedHashMap<String,String> columns;
		LinkedHashMap<String,HashMap<String,String>> records;

		list = null;
		records = new LinkedHashMap<String,HashMap<String,String>>();
		selectRequest = new SelectRequest(query).withConsistentRead( true );
		selectResult = sdb.select( selectRequest );

		// 検索した結果を取得する
		items1 = selectResult.getItems();
		for(int idx1 = 0;idx1 < items1.size();idx1++){
			key = items1.get(idx1).getName();
			columns = new LinkedHashMap<String,String>();
			// 主キー以外のデータを取得
			for (Iterator<Attribute> i = items1.get(idx1).getAttributes().listIterator(); i.hasNext();) {
				att = i.next();
				columns.put(att.getName(), att.getValue());
			}
			records.put(key, columns);
		}

		list = convertPojo(pojo.getClass(), pojo.getColumns(), records);

		return list;
	}

	/**
	 * HashMapをデータクラスへ変換
	 *
	 * @param pojo
	 * @param columns
	 * @param data
	 * @return
	 */
	private static List<?> convertPojo(Class<?> pojo,String[] columns,LinkedHashMap<String,HashMap<String,String>> data) throws Exception{
		Object obj;
		List<Object> list;
		HashMap<String,String> columndatas;

		list = null;
		if(data != null){
			list = new ArrayList<Object>();
			for (Object id : data.keySet()) {
				obj = pojo.newInstance();
	        	// IDの設定
	        	Common.setFieldValueByName(obj,"id", id);
	        	columndatas = data.get(id);
	        	// カラム数分
	        	for(int idx = 0;idx < columns.length;idx++){
	        		if(columndatas.containsKey(columns[idx])){
	        			Common.setFieldValueByName(obj,columns[idx],columndatas.get(columns[idx]));
	        		}
	        	}
	        	list.add(obj);
			}
		}

		return list;
	}
}
